<template>
  <div class="waterfall-container" ref="containerRef">
    <div
      v-for="(item, index) in items"
      :key="item.id || index"
      class="waterfall-item"
      :style="getItemStyle(index)"
      @load="handleItemLoad"
    >
      <slot :item="item" :index="index"></slot>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, nextTick, watch, onBeforeUnmount } from 'vue'

interface Props {
  items: any[]
  columns?: number
  gap?: number
  minColumnWidth?: number
}

const props = withDefaults(defineProps<Props>(), {
  columns: 0,
  gap: 16,
  minColumnWidth: 300
})

const containerRef = ref<HTMLElement>()
const itemPositions = ref<{ left: number; top: number; width: number }[]>([])
const columnHeights = ref<number[]>([])
const actualColumns = ref(3)
const containerWidth = ref(0)

// 计算列数
const calculateColumns = () => {
  if (props.columns > 0) {
    actualColumns.value = props.columns
  } else if (containerRef.value) {
    const width = containerRef.value.clientWidth
    containerWidth.value = width
    const maxColumns = Math.floor(width / props.minColumnWidth)
    actualColumns.value = Math.max(1, maxColumns)
  }
  
  // 初始化列高度
  columnHeights.value = new Array(actualColumns.value).fill(0)
}

// 计算单个项目的样式
const getItemStyle = (index: number) => {
  if (!itemPositions.value[index]) {
    return {
      position: 'absolute' as const,
      visibility: 'hidden' as const
    }
  }
  
  const position = itemPositions.value[index]
  return {
    position: 'absolute' as const,
    left: `${position.left}px`,
    top: `${position.top}px`,
    width: `${position.width}px`,
    visibility: 'visible' as const
  }
}

// 计算项目位置
const calculateItemPositions = async () => {
  if (!containerRef.value || !props.items.length) return

  await nextTick()
  
  const containerWidth = containerRef.value.clientWidth
  const columnWidth = Math.floor((containerWidth - props.gap * (actualColumns.value - 1)) / actualColumns.value)
  
  // 重置列高度
  columnHeights.value = new Array(actualColumns.value).fill(0)
  
  const newPositions: { left: number; top: number; width: number }[] = []
  
  // 先让所有元素显示以获取高度
  const items = containerRef.value.querySelectorAll('.waterfall-item')
  
  for (let i = 0; i < props.items.length; i++) {
    // 找到最短的列
    const shortestColumnIndex = columnHeights.value.indexOf(Math.min(...columnHeights.value))
    
    // 计算位置
    const left = shortestColumnIndex * (columnWidth + props.gap)
    const top = columnHeights.value[shortestColumnIndex]
    
    // 获取元素实际高度
    let itemHeight = 200 // 默认高度
    if (items[i]) {
      // 先设置临时样式以获取实际高度
      const element = items[i] as HTMLElement
      element.style.position = 'static'
      element.style.visibility = 'visible'
      element.style.width = `${columnWidth}px`
      
      // 等待下一帧确保样式应用
      await new Promise(resolve => requestAnimationFrame(resolve))
      
      itemHeight = element.offsetHeight
    }
    
    newPositions.push({
      left,
      top,
      width: columnWidth
    })
    
    // 更新列高度
    columnHeights.value[shortestColumnIndex] += itemHeight + props.gap
  }
  
  itemPositions.value = newPositions
  
  // 设置容器高度
  const maxHeight = Math.max(...columnHeights.value)
  if (containerRef.value) {
    containerRef.value.style.height = `${maxHeight}px`
  }
}

// 处理项目内容加载完成
const handleItemLoad = () => {
  calculateItemPositions()
}

// 监听窗口大小变化
const handleResize = () => {
  calculateColumns()
  calculateItemPositions()
}

// 监听数据变化
watch(() => props.items, () => {
  nextTick(() => {
    calculateItemPositions()
  })
}, { deep: true })

// 监听列数配置变化
watch(() => [props.columns, props.minColumnWidth], () => {
  calculateColumns()
  calculateItemPositions()
})

onMounted(() => {
  calculateColumns()
  nextTick(() => {
    calculateItemPositions()
  })
  
  window.addEventListener('resize', handleResize)
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', handleResize)
})

// 暴露重新计算方法
defineExpose({
  recalculate: calculateItemPositions
})
</script>

<style scoped>
.waterfall-container {
  position: relative;
  width: 100%;
  min-height: 200px;
}

.waterfall-item {
  position: absolute;
  transition: all 0.3s ease;
}
</style>